/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gblend.largegraph.structure;

import gblend.adjlistgraph.FsgIdEntry;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;

/**
 * To facilitate (suppose) faster similar candidate intersection
 * @author HO HOANG HUNG
 */
public class SInterSet {

    ArrayList<FsgIdEntry> orderedset = new ArrayList<FsgIdEntry>();
    HashSet<FsgIdEntry> intersectSet = new HashSet<FsgIdEntry>();
    HashSet<FsgIdEntry> firstSet = new HashSet<FsgIdEntry>();
    HashSet<FsgIdEntry> secondSet = new HashSet<FsgIdEntry>();
    HashMap<Integer, ArrayList<Integer>> hashtree = new HashMap<Integer, ArrayList<Integer>>();

    /*public boolean isEmpty() {
    return intersectSet.isEmpty();
    }

    public HashSet<FsgIdEntry> getSet() {
    return intersectSet;
    }*/
    public ArrayList<FsgIdEntry> getOrderedSet() {
        return orderedset;
    }

    public HashSet<FsgIdEntry> getSet() {
        return intersectSet;
    }
    /*public void addAll(HashSet<FsgIdEntry> idset) {
    Iterator<FsgIdEntry> idsi = idset.iterator();
    while (idsi.hasNext()) {
    FsgIdEntry idsie = idsi.next();
    if (!intersectSet.contains(idsie)) {
    intersectSet.add(idsie);
    orderedset.add(idsie);
    int index = orderedset.size() - 1;
    addEntryToHashTree(hashtree, idsie, index);
    }
    }
    }*/

    private void add(FsgIdEntry newentry) {
        if (intersectSet.add(newentry)) {
            //  System.out.println("Insert new entry = " + newentry.toString());
            int index = orderedset.size();
            orderedset.add(newentry);
            addEntryToHashTree(hashtree, newentry, index);
        }
    }

    private static void addInIntersect(FsgIdEntry newentry, HashSet<FsgIdEntry> itss, ArrayList<FsgIdEntry> ods, HashMap<Integer, ArrayList<Integer>> ht) {
        if (itss.add(newentry)) {
            //  System.out.println("Insert new entry = " + newentry.toString());
            int index = ods.size();
            ods.add(newentry);
            addEntryToHashTree(ht, newentry, index);
        }
    }

    public void addSecondSet(HashSet<FsgIdEntry> sset) {
        System.out.print(">>> TO ADD 2ND SET of size="+sset.size());
        if (firstSet.size() == 0) {
            firstSet = new HashSet<FsgIdEntry>(sset);
            return;
        }
        if (secondSet.size() == 0) {
            secondSet = new HashSet<FsgIdEntry>(sset);
            return;
        }
        if (secondSet.size() > firstSet.size()) {
            if (sset.size() > firstSet.size()) {
                firstSet = new HashSet<FsgIdEntry>(sset);
            }
        } else {
            if (sset.size() > secondSet.size()) {
                secondSet = new HashSet<FsgIdEntry>(sset);
            }
        }
    }

    public void finalCombine() throws Exception {
        if(secondSet.size()==0){
            throw new Exception("WRONG SECOND SET SIZE");
        }
        Iterator<FsgIdEntry> newsi = firstSet.iterator();
        while (newsi.hasNext()) {
            FsgIdEntry newsie = newsi.next();
            this.add(newsie);
        }
        intersect(this, secondSet);
        System.out.println(" ***** FinalCombine ALR");
    }

    private static void intersect(SInterSet src, HashSet<FsgIdEntry> newset) {
        // src.print();
        //   IntersectSet result = new IntersectSet();
        HashSet<FsgIdEntry> itss = new HashSet<FsgIdEntry>();
        ArrayList<FsgIdEntry> ods = new ArrayList<FsgIdEntry>();
        HashMap<Integer, ArrayList<Integer>> ht = new HashMap<Integer, ArrayList<Integer>>();
        Iterator<FsgIdEntry> entryi = newset.iterator();
        while (entryi.hasNext()) {
            FsgIdEntry entryie = entryi.next();
            //  System.out.println("Current entry is " + entryie.toString());
            //Keep track of what entry in vector has already been combined with this entry
            HashSet<Integer> combined = new HashSet<Integer>();
            Iterator<Integer> entryieids = entryie.getGraphId().iterator();
            while (entryieids.hasNext()) {
                ArrayList<Integer> targetentry = src.hashtree.get(entryieids.next());
                if (targetentry != null) {
                    combined.addAll(targetentry);
                }
            }
            Iterator<Integer> indexl = combined.iterator();
            while (indexl.hasNext()) {
                FsgIdEntry centry = FsgIdEntry.combine(src.orderedset.get(indexl.next()), entryie);
                addInIntersect(centry, itss, ods, ht);
                //    result.add(centry);
                //addEntryToHashTree(temptree, centry, tempresult.size() - 1);
            }
        }
        //   Iterator<FsgIdEntry> outscr = result.orderedset.iterator();
        //  System.out.println("intersect set output:");
        //   while (outscr.hasNext()) {
        //      System.out.print(outscr.next().toString() + ", ");
        //   }
        //   System.out.println();
        src.hashtree = new HashMap<Integer, ArrayList<Integer>>(ht);
        src.intersectSet = new HashSet<FsgIdEntry>(itss);
        src.orderedset = new ArrayList<FsgIdEntry>(ods);
        //   return result;
    }

    private static void addEntryToHashTree(HashMap<Integer, ArrayList<Integer>> hashtree, FsgIdEntry entryie, int i) {
        Iterator<Integer> entryieids = entryie.getGraphId().iterator();
        while (entryieids.hasNext()) {
            int eid = entryieids.next();
            ArrayList<Integer> temp = hashtree.get(eid);
            if (temp == null) {
                temp = new ArrayList<Integer>();
                temp.add(i);
                hashtree.put(eid, temp);
            } else {
                temp.add(i);
            }
        }
    }

    public static void main(String[] args) {
        int[] test = new int[2000];
        for (int i = 0; i < test.length; i++) {
            test[i] = (int) (Math.random() * 3000);
        }
        /*LinkedHashSet<Integer> testl = new LinkedHashSet<Integer>();
        for(int i=0;i<test.length;i++){
        testl.add(test[i]);
        }

        Iterator<Integer> testli = testl.iterator();
        int j=0;
        while(testli.hasNext()){
        int t =testli.next();
        if(t!=test[j]){
        System.out.println("WRONG testli="+t+" test[j]="+test[j]+" with j="+j);
        return;
        }
        j++;
        }
        System.out.println("testl is correct");*/
        ArrayList<Integer> testv = new ArrayList<Integer>();
        for (int i = 0; i < test.length; i++) {
            testv.add(test[i]);
        }
        for (int i = 0; i < test.length; i++) {
            if (testv.get(i) != test[i]) {
                System.out.println("WRONGGGG testv at i=" + testv.get(i) + " test[i]=" + test[i]);
                return;
            }
        }

        System.out.println("COREECT");
    }

    public void print() {
        Iterator<FsgIdEntry> isi = intersectSet.iterator();
        System.out.print("Intersect content is");
        while (isi.hasNext()) {
            System.out.print(" " + isi.next());
        }
        System.out.println();
    }

    public boolean isEmpty() {
        return firstSet.isEmpty();
    }


}
